# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/micropython-esp32-bluetooth-low-energy-ble/

from micropython import const
import asyncio
import aioble
import bluetooth
import struct
from machine import Pin
from random import randint
import binascii


# Init LED
led = Pin(2, Pin.OUT)
led.value(0)

# Init random value
value = 0

# See the following for generating UUIDs:
# https://www.uuidgenerator.net/
_BLE_SERVICE_UUID = bluetooth.UUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b")
_BLE_META_CHAR_UUID = bluetooth.UUID("19b10002-e8f2-537e-4f6c-d104768a1214")
_BLE_DATA_UUID = bluetooth.UUID('beb5483e-36e1-4688-b7f5-ea07361b26a8')
# How frequently to send advertising beacons.
_ADV_INTERVAL_MS = 250_000

# Register GATT server, the service and characteristics
ble_service = aioble.Service(_BLE_SERVICE_UUID)
meta_characteristic = aioble.Characteristic(ble_service, _BLE_META_CHAR_UUID, read=True, notify=True)
data_characteristic = aioble.Characteristic(ble_service, _BLE_DATA_UUID, read=True, write=True, notify=True, capture=True)

# Register service(s)
aioble.register_services(ble_service)

# 控制传输的meta信息
meta_chunks_total = -1
meta_chunks_number = -1
meta_chunks_hex = ""

def utf8_string_to_hex_uint8array(text):
    """
    Converts a UTF-8 string to a hex-encoded Uint8Array.

    Args:
        text: The UTF-8 string to convert.

    Returns:
        A string representing the hex-encoded Uint8Array.
    """
    utf8_bytes = text.encode('utf-8')
    hex_string = ''.join([f'{byte:02x}' for byte in utf8_bytes])
    return hex_string




# Helper to encode the data characteristic UTF-8
def _encode_data(data):
    return str(data).encode('utf-8')

# Helper to decode the LED characteristic encoding (bytes).
def _decode_data(data):
    try:
        if data is not None:
            # Decode the UTF-8 data
            number = int.from_bytes(data, 'big')
            return number
    except Exception as e:
        print("Error decoding temperature:", e)
        return None

# Get meta readings
def get_random_value():
    return randint(0,100)

# Get new value and update characteristic
async def meta_task():
    while True:
        value = get_random_value()
        meta_characteristic.write(_encode_data(value), send_update=True)
        print('New random value written: ', value)
        await asyncio.sleep_ms(1000)
        
# Serially wait for connections. Don't advertise while a central is connected.
async def peripheral_task():
    while True:
        try:
            async with await aioble.advertise(
                _ADV_INTERVAL_MS,
                name="TrueTalk",
                services=[_BLE_SERVICE_UUID],
                ) as connection:
                    print("Connection from", connection.device)
                    await connection.disconnected()             
        except asyncio.CancelledError:
            # Catch the CancelledError
            print("Peripheral task cancelled")
        except Exception as e:
            print("Error in peripheral_task:", e)
        finally:
            # Ensure the loop continues to the next iteration
            await asyncio.sleep_ms(100)

async def wait_for_write():
    while True:
        try:
            connection, data = await data_characteristic.written()
            print(data)
            print(type)
            
            
            # 先判断是不是第一个传输
            
            #
            hex_string = binascii.hexlify(data)
            print(hex_string)
            
            byte_array = bytes.fromhex(hex_string)
            string_china = byte_array.decode('utf-8', 'ignore')
            print(string_china)
            
            value = "OK"
            data_characteristic.write(_encode_data(value), send_update=True)
            
#             byte_array = bytes.fromhex(hex_string)
#             string_china = byte_array.decode('utf-8')
#             print(string_china)
            
        except asyncio.CancelledError:
            # Catch the CancelledError
            print("Peripheral task cancelled")
        except Exception as e:
            print("Error in peripheral_task:", e)
        finally:
            # Ensure the loop continues to the next iteration
            await asyncio.sleep_ms(100)
            
# Run tasks
async def main():
    # t1 = asyncio.create_task(meta_task())
    t2 = asyncio.create_task(peripheral_task())
    t3 = asyncio.create_task(wait_for_write())
    await asyncio.gather(t2, t3)
    
asyncio.run(main())
